/*
	Alan Fortes
	cpe 301, 3/14/15, Design Assignment 2
	
	The following C program, meant to run on the ATMega328p,
	does the following:
	 
   *Creates a square wave with a period of 0.5 seconds, and
	a duty cycle of 0.5. This is done through using a delay
	subroutine to toggle a signal via one of the ports.
	This square wave is output through PORTB.5, and represented 
	by the 9th LED of a 10 LED bar.
   
   *Runs an 8 bit counter that is output by PORTD.
    The output of this counter is represented by the 
	first 8 LEDs of the previously mentioned LED bar.
	Overflow is unaccounted for and simply rolls the 
	counter back to the very beginning of a zero count.
   
   *Toggles on and off PORTB.4 on every 5th rising edge of the 
    previously mentioned square wave. The status of PORTB.4 is 
	represented by the 10th LED of the previously mentioned LED bar.
   
   *Uses an interrupt to toggle PORTB.4.
	
   The LED bar's LED positions are counted so that the 1st LED
   is the rightmost LED, and the last LED is the 10th. 	 
   
   Since the counter will be toggled on every rising edge, there will 
   be 2 delay loops, each having a delay of 0.25 seconds, using CTC 
   mode. Our square wave will start low and will rise high after the
   first delay, triggering the counter. After the 2nd delay loop, 
   
   The value the OCR will be:
   
   8000000 * 0.25 / 1024 = 1953.125, rounding down, 1953, or 07A1 in hexadecimal.   
*/

#include <avr/io.h>        // Here, the header for accepting inputs and outputs is declared.
#include <avr/interrupt.h> // Here, the header for activating interrupts is declared.


int main(void)
{
	int periodsPassed = 1; // This value represents the starting position of
						   // first square wave generated. Since the starting
						   // position of our first square is a low, and the
						   // waves are detected on highs, we will need to  								  
						   // advance our initial value of periodsThatHavePassed
						   // to be one, so that it may correctly be activated 
						   // on the next rising edge. 
	
	DDRB = 0x30; // Setting the value of DDRB to 30 in hex, 48 in decimal, 
				 //	allows PORTB.4 and PORTB.5 to output values. 48 in decimal 
				 // is 32 + 16, which corresponds to binary value of 00110000, 
				 // which indicates that PORTB.4, the fifth pin of PORTB, and 
				 // PORTB.5, the sixth pin of PORTB, are able to transmit output.
				 	
	DDRD = 0xFF; // Setting the value of DDRD to FF in hex, 255 in decimal, 
				 // allows for all of PORTD to output values. 255 in decimal 
				 // is 128 + 64 + 32 + 16 + 8 + 4 + 2 + 1, which corresponds 
				 // to binary value of 11111111, which indicates that all 8 
				 // pins of PORTB are able to transmit output.
	
	TCCR1A = 0x00; // The value of TCCR1A is set to be zero, meaning TCNT1 will be clock driven.
	
	TCCR1B = 0x0D; // The value of TCCR1B is set to D in hex, 13 is decimal, to do 2 things:
	               // First, set the mode of timer 1 to be CTC mode. WGM12 is the 4th bit of 
				   // the TCCR1A register, and 8 corresponds to this bit.
				   // Second, set the prescaler to be 1024. The 1st and 3rd pin of the TCCR1B
				   // correspond to this prescaler. 
	
	OCR1A = 0x07A1; // The value of the overflow compare register is given a hexadecimal value of 07A1,
	                // or 1953 in decimal.
	
	TIMSK0 |= (1 << TOIE0); // The timer overflow interrupt enable 0 flag  is set in the timer
	                        // interrupt mask register 0, we may induce an interrupt, when needed.

	sei(); // The set interrupt flag is activated.
	
	while(1){
						
	   	while((TIFR1 & (1<<OCF1A)) == 0){ // This loop will cause a delay for 1953 clock cycles, prescaled at 1024.
		//Wait for 0.25 seconds.	  
		} 
					   			  						
		TIFR1 |= (1 << OCF1A); // The timer interrupt flag register's overflow compare flag 1A is reset. 
		
		PORTB ^= 32; //Here, PORTB.5 is toggled to be high.
		
		PORTD++;     // The value of PORTD is incremented, and thus the counter is updated.
		             // This only occurs right after the value of PORTB.5 is set high,
					 // so that the counter increments on a rising edge. 
		
		if(((periodsPassed) % 5) == 0){ // This if statement checks to see if 5 clock cycles have elapsed.
												// If this is so, then the sequence of events to force an interrupt
												// to occur will occur.
			
			periodsPassed = 0; // Here, the number of counted periods is reset,
									   // after the 5th rising edge has been detected
						  
			TCNT0 = 0xFF; // The value of TCNT0 is increased to its maximum,
						  // so that the overflow flag of register TIFR0 can 
						  // be activated the moment the TCNT0 register overflows.
			
			TCCR0B = 1;   // Here, the value of TCCR0B is set to 1, so that the 
			              // TOV0 flag will is capable of being triggered. 			
			
			TCNT0 += 1;   // TCNT0 is incremented by one to induce an overflow, 
						  // thus activating the TOV0 overflow bit of the TIFR0
		}                 // can cause the ISR function to toggle PORTB.4.
		
		
		while((TIFR1 & (1<<OCF1A)) == 0){ // This loop will cause a delay for 1953 clock cycles, prescaled at 1024.
		//Wait for 0.25 seconds.	  
		} 
							  						
		
		TIFR1 |= (1 << OCF1A); // The timer interrupt flag register's overflow compare flag 1A is reset.
		
		PORTB ^= 32;		   //Here, PORTB.5 is toggled to be low.
		
		periodsPassed++; // Here, the number clock cycles that have elapsed
		                         // is incremented to keep track of when the 5th one
								 // has come. 
	}
}


ISR(TIMER0_OVF_vect){

	TCCR0B = 0;  // The mode of TCNT0 is set to be no clock,
				 // since there is no need for it to be counting.
				 // A counting TCNT0 would cause the TOV0 flag to
				 // to be unnecessarily set off, since the maximum
				 // value of TCNT0 is 255, and we are counting to 
				 // a TCNT1 value of 1953.
				 
	PORTB ^= 0x10; // Here, PORTB.4 is toggled. 
}
